<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\Common\Robot\Robot;
use App\CustHub\Amqp\Producers\CommonTaskCenterProducers;
use App\CustHub\Constants\RoomTaskCenterStatusConstants;
use App\CustHub\Constants\RoomTaskCenterTypeConstants;
use App\CustHub\Dto\CommonProducersDto;
use App\CustHub\Dto\RoomTcContentDto;
use App\CustHub\Event\RoomOperationBehaviorAfter;
use App\CustHub\Event\SopRoomTrigger;
use App\CustHub\Helpers\TagReplacer;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChRoomTaskCenterMapper;
use App\CustHub\Mapper\ChUserMapper;
use App\CustHub\Model\ChRoom;
use App\CustHub\Model\ChRoomRobot;
use App\Robot\Service\RobotApiService;
use Hyperf\Amqp\Producer;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\MineModel;
use Psr\EventDispatcher\EventDispatcherInterface;

/**
 * 群任务中心服务类
 */
class ChRoomTaskCenterService extends AbstractService
{
    public $mapper;

    #[Inject]
    private EventDispatcherInterface $eventDispatcher;

    #[Inject]
    public ChRobotMapper $robotMapper;

    public function __construct(ChRoomTaskCenterMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    public function list(array $params): array
    {
        return $this->mapper->listPage($params);
    }

    /**
     * 新增任务
     * @param mixed $uid
     * @param mixed $mainUid
     * @param int $type
     * @param RoomTcContentDto $content
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function addTask(mixed $uid,mixed $mainUid,int $type,RoomTcContentDto $content,int $delay = 0): bool
    {
        $totalCount = is_array($content->getRoomIds()) ? count($content->getRoomIds()) : 1;
        if($uid == $mainUid){
            $operator = '主账号';
        }else{
            $userInfo = container()->get(ChUserMapper::class)->findById($uid);
            $operator = $userInfo->nickname;
        }
        $taskData = [
            'uid' => $uid,
            'main_uid' => $mainUid,
            'type' => $type,
            'content' => $content->__toArray(),
            'total_count' => $totalCount,
            'operator' => $operator,
        ];

        $taskId =  $this->mapper->save($taskData);
        return container()->get(Producer::class)->produce(new CommonTaskCenterProducers(new CommonProducersDto(
            classname: ChRoomTaskCenterService::class,
            method: 'handleTask',
            data: ['task_id' => $taskId],
            delay: $delay
        )));
    }

    /**
     * 执行任务
     * @param array $data
     * @return void
     */
    #[Transaction]
    public function handleTask(array $data): void
    {
        $taskInfo = $this->mapper->findById($data['task_id']);
        if(empty($taskInfo) || $taskInfo['status'] != RoomTaskCenterStatusConstants::IN_PROGRESS){
            return;
        }

        $successCount = 0;
        $roomIds = $taskInfo->content['roomIds'];
        $tagIds = $taskInfo->content['tagIds'];
        $removeTagIds = $taskInfo->content['removeTagIds'];
        $extra = $taskInfo->content['extra'];

        $roomList = ChRoom::query()
            ->select(['id','room_name','room_wxid'])
            ->with(['robots'=>function ($query) {
                $query->select(['id','login_status','server_id','robot_key','uuid']);
            }])
            ->where(function ($query) use ($roomIds){
                if(is_array($roomIds)){
                    $query->whereIn('id',$roomIds);
                }else{
                    $query->where('id',$roomIds);
                }
            })
            ->get();


        switch ($taskInfo->type){
            case RoomTaskCenterTypeConstants::TAG:
                //打标签
                foreach ($roomList as $room){
                    $room->roomTags()->sync($tagIds,false);
                    //记录群聊行为日志
                    event(new RoomOperationBehaviorAfter($room['id'],$taskInfo->type,[
                        'tagIds' => $tagIds
                    ]));
                    $successCount++;
                }
                break;
            case RoomTaskCenterTypeConstants::REMOVE_TAG:
                //删除标签
                foreach ($roomList as $room){
                    $room->roomTags()->detach($removeTagIds);
                    //记录群聊行为日志
                    event(new RoomOperationBehaviorAfter($room['id'],$taskInfo->type,[
                        'tagIds' => $tagIds
                    ]));
                    $successCount++;
                }
                break;
            case RoomTaskCenterTypeConstants::MOVE_TAG:
                //移动标签
                foreach ($roomList as $room){
                    $room->roomTags()->detach($removeTagIds);
                    $room->roomTags()->sync($tagIds,false);
                    //记录群聊行为日志
                    event(new RoomOperationBehaviorAfter($room['id'],$taskInfo->type,[
                        'tagIds' => $tagIds,
                        'removeTagIds' => $removeTagIds
                    ]));
                    $successCount++;
                }
                break;
            case RoomTaskCenterTypeConstants::CHANGE_ROOM_NAME:
                //修改群名称
                $successCount = $this->changeRoomName($taskInfo->uid,$taskInfo->main_uid,$roomList->toArray(),$extra);
                break;
            case RoomTaskCenterTypeConstants::TRANSFER_ROOM_OWNER:
                //转让群主
                $successCount = $this->changeRoomOwner($taskInfo->uid,$taskInfo->main_uid,$extra['robot_id'],$roomList->toArray(),$extra['newOwnerUserId']);
                break;
            case RoomTaskCenterTypeConstants::SET_ROOM_ADMIN:
                //设置群管理员
                $successCount = $this->setRoomAdmin($taskInfo->uid,$taskInfo->main_uid,$extra['robot_id'],$roomList->toArray(),$extra['adminUserId']);
                break;
            case RoomTaskCenterTypeConstants::SAVE_TO_CONTACTS:
                //保存到通讯录
                $successCount = $this->saveContacts($roomList->toArray(),5);
                break;
            case RoomTaskCenterTypeConstants::UNSAVE_FROM_CONTACTS:
                //取消保存到通讯录
                $successCount = $this->saveContacts($roomList->toArray(),6);
                break;
            case RoomTaskCenterTypeConstants::SET_ROOM_DO_NOT_DISTURB;
                //设置群免打扰
                $rst = $this->setRoomDoNotDisturb($roomList->toArray(),$extra['robot_id'],$extra['type']);
                $rst && $successCount = $taskInfo->total_count;
                break;
            default:
                logger()->info('暂不支持当前类型type:'.$taskInfo->type);
                break;
        }


        //变更任务执行情况
        $this->mapper->update($taskInfo->id,[
            'status' => RoomTaskCenterStatusConstants::COMPLETED,
            'success_count' => $successCount,
            'fail_count' => $taskInfo->total_count - $successCount
        ]);
        //触发群sop
        $this->eventDispatcher->dispatch(new SopRoomTrigger($roomIds));
    }

    private function changeRoomName(int $uid,int $mainUid,array $roomList,array $extra): int
    {
        $successCount = 0;
        $roomOp = container()->get(ChConfigService::class)->getConfigByGroupKey($uid,$mainUid,'room_op');
        $changeRoomOwnerInterval = $roomOp['change_room_owner_interval']['value'];
        $min = $changeRoomOwnerInterval['min'] ?? 5;
        $max = $changeRoomOwnerInterval['max'] ?? 10;

        $type = $extra['type'];

        $numberStart = $extra['number_start'] ?? 0;
        foreach ($roomList as $room){
            $robots = $room['robots'];
            $onlineRobots = array_filter($robots,function ($item){
                return $item['login_status'] == 1;
            });
            if(empty($onlineRobots)){
                continue;
            }
            if($type == 1){
                $roomName = str_replace($extra['keyword'],$extra['replace_str'],$room['room_name']);
            }else{
               $roomName = TagReplacer::replaceTags($extra['room_name'],[
                    'room_name' => $room['room_name'],
                    'number' => $numberStart
                ]);
            }

            $robot = array_shift($onlineRobots);
            $service = make(\App\Common\Robot\Robot::class,[$robot['server_id'],$robot['uuid']])->gateway();
            $result = $service->editRoomName($room['room_wxid'],$roomName);
            if($result !== false){
                $successCount++;
                $numberStart++;

                ChRoom::query()->where('id',$room['id'])->update([
                    'room_name' => $roomName,
                ]);

                event(new RoomOperationBehaviorAfter($room['id'], RoomTaskCenterTypeConstants::CHANGE_ROOM_NAME, [
                    'roomName' => $roomName,
                ]));
            }
            Coroutine::sleep(mt_rand($min,$max));
        }
        return $successCount;
    }

    private function changeRoomOwner(int $uid,int $mainUid,int $robotId,array $roomList,string $newOwnerId): int
    {
        $successCount = 0;
        $roomOp = container()->get(ChConfigService::class)->getConfigByGroupKey($uid,$mainUid,'room_op');
        $changeRoomOwnerInterval = $roomOp['change_room_owner_interval']['value'];
        $min = $changeRoomOwnerInterval['min'] ?? 5;
        $max = $changeRoomOwnerInterval['max'] ?? 10;
        $robotInfo = $this->robotMapper->findById($robotId);
        if(empty($robotInfo) || $robotInfo['login_status'] != 1){
            return $successCount;
        }

        $service =  make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();
        foreach ($roomList as $k=>$room){
            $result = $service->transferRoomOwner($room['room_wxid'],$newOwnerId);
            if($result !== false){
                $successCount++;
            }
            Coroutine::sleep(mt_rand($min,$max));
        }
        return $successCount;
    }

    private function setRoomAdmin(int $uid,int $mainUid,int $robotId,array $roomList,string $adminUserId): int
    {
        $successCount = 0;
        $roomOp = container()->get(ChConfigService::class)->getConfigByGroupKey($uid,$mainUid,'room_op');
        $changeRoomOwnerInterval = $roomOp['change_room_owner_interval']['value'];
        $min = $changeRoomOwnerInterval['min'] ?? 5;
        $max = $changeRoomOwnerInterval['max'] ?? 10;
        $robotInfo = $this->robotMapper->findById($robotId);
        if(empty($robotInfo) || $robotInfo['login_status'] != 1){
            return $successCount;
        }

        $service =  make(Robot::class, [$robotInfo->server_id, $robotInfo->uuid])->gateway();

        $adminUserRobot = $this->robotMapper->findByUserId($adminUserId,$mainUid);

        foreach ($roomList as $room){
            $result = $service->setRoomAdmin($room['room_wxid'],[$adminUserId]);
            if($result !== false){
                $successCount++;
                event(new RoomOperationBehaviorAfter($room['id'],RoomTaskCenterTypeConstants::CHANGE_ROOM_NAME,[
                    'nickname' =>$adminUserRobot->nickname,
                ]));
            }
            Coroutine::sleep(mt_rand($min,$max));
        }

        return $successCount;
    }

    public function saveContacts(array $roomList,int $type): int
    {
        $successCount = 0;
        foreach ($roomList as $room){
            $rs = 0;
            foreach ($room['robots'] as $robot){
                if($robot['login_status'] != 1){
                    continue;
                }
                $service =  make(Robot::class, [$robot['server_id'], $robot['uuid']])->gateway();
                $rst = $service->setSessionCmd($room['room_wxid'],$type);
                if($rst !== false){
                    $rs++;
                    ChRoomRobot::query()
                        ->where('room_id',$room['id'])
                        ->where('robot_id',$robot['id'])
                        ->update([
                            'is_saved' => $type == 5 ? 1 : 0
                        ]);
                }
            }
            if($rs){
                $successCount++;
            }
        }
        return $successCount;
    }

    private function setRoomDoNotDisturb($roomList,$robotIds,$type): bool
    {
        $count = 0;
        foreach ($roomList as $room){
            foreach ($robotIds as $robotId){
                $robot = $this->robotMapper->findById($robotId);
                if(empty($robot) || $robot['login_status'] != 1){
                    continue;
                }
                $service = make(Robot::class, [$robot->server_id, $robot->robot_key])->gateway();
                $rst = $service->setSessionCmd($room['room_wxid'],$type);
                if($rst !== false){
                    $count++;
                    ChRoomRobot::query()
                        ->where('room_id',$room['id'])
                        ->where('robot_id',$robotId)
                        ->update([
                            'is_do_not_disturb' => $type == 3 ? 1 : 0
                        ]);
                }
            }
        }
        return $count > 0;
    }

}